
import java.util.ArrayList;

import org.jbox2d.collision.CircleDef;
import org.jbox2d.collision.Shape;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.joints.RevoluteJointDef;

import pulpfizz.physics.BodyUtils;
import pulpfizz.physics.ContactData;
import pulpfizz.physics.ContactEventListener;
import pulpfizz.physics.Material;
import pulpfizz.physics.NewWorld;
import pulpfizz.physics.ShapeData;

public class PuckMaker {
    public static float puckDensity = 4.0f;
    static boolean listenerNotSet = true;

    static public int count = 0;
    static public ArrayList<Body> createSquareBlob(float x0, float y0,
												   float x1, float y1,
												   int nx, int ny,
												   NewWorld world) {
		ArrayList<Body> pieces = new ArrayList<Body>();
		float dx = (x1-x0)/nx;
		float dy = (y1-y0)/ny;
		Vec2 loc = new Vec2(x0+dx*.5f,y0+dy*.5f);
		for (int i=0; i<nx; ++i) {
			for (int j=0; j<ny; ++j) {
				Body piece = BodyUtils.createBox(world, loc.x, loc.y, dx, dy);
				piece.setMassFromShapes();
				//piece.getShapeList().m_groupIndex = -20;
				Material m = new Material();
                m.setRestitution(0.4f);

                m.setDensity(puckDensity);
                m.applyAll(piece);
				CircleDef cd = new CircleDef();
				cd.isSensor = true;
                cd.groupIndex = -30;
                cd.density = 0.0f;
				cd.radius = dx*1.4f;
				cd.localPosition = piece.getLocalCenter();
				Shape sensor = piece.createShape(cd);
				ShapeData sdata = new ShapeData();
				sdata.addToGroup(PulpFireScene.BLOB_GROUP);
				sdata.addShape(sensor);
				pieces.add(piece);
                piece.setBullet(false);
                loc.y += dy;
			}
			loc.y = y0+dy*.5f;
			loc.x += dx;
		}

        if (listenerNotSet) {
        	ContactEventListener listener = new ContactEventListener(){
        		private final float forceFactor = 3.0f*puckDensity/10.0f;
        		private final float forceDamping = 1.2f*puckDensity/10.0f;
        		public void trigger(ContactData c) {
        			++PuckMaker.count;
                    if (c.state != ContactData.PERSIST) return;

                    Body b1 = c.shape1.getBody();
        			Body b2 = c.shape2.getBody();
        			if (   !(    ((ShapeData)b1.getShapeList().getUserData()).isInGroup(PulpFireScene.BLOB_GROUP)
        					&& ((ShapeData)b2.getShapeList().getUserData()).isInGroup(PulpFireScene.BLOB_GROUP)
        			) ) return;

                    //Vec2 disp = b2.getWorldCenter().sub(b1.getWorldCenter());
        			//Vec2 vrel = b2.getLinearVelocity().sub(b1.getLinearVelocity());
                    Vec2 b2c = b2.getWorldCenter();
                    Vec2 b1c = b1.getWorldCenter();
                    float dispx = b2c.x-b1c.x;
                    float dispy = b2c.y-b1c.y;
                    //float dist = disp.normalize();
                    float distsqr = dispx*dispx+dispy*dispy;
                    if (distsqr < 0.2f*0.2f) return;
                    float vrelx = b2.getLinearVelocity().x-b1.getLinearVelocity().x;
                    float vrely = b2.getLinearVelocity().y-b1.getLinearVelocity().y;
                    float dist = (float)Math.sqrt(distsqr);
                    dispx /= dist;
                    dispy /= dist;
                    float vrelproj = vrelx*dispx+vrely*dispy;
        			float force = forceFactor * dist + forceDamping*vrelproj;
        			dispx *= force;
                    dispy *= force;
                    Vec2 disp = new Vec2(dispx,dispy);
                    b1.applyForce(disp, b1.getWorldCenter());
                    disp.mulLocal(-1.0f);
                    b2.applyForce(disp, b2.getWorldCenter());
        		}
        	};
		
            world.getContactEventDispatcher().registerGroupListener(PulpFireScene.BLOB_GROUP, listener);
            listenerNotSet = false;
        }
        return pieces;
	}
	
	static public Body createPuck(float x, float y, float size, NewWorld world) {
		return createTendrilPuck(x, y, size, world);
	}
	
	static public Body createTendrilPuck(float x, float y, float size, NewWorld world) {
		int tendrils = 8;
		float tendrilLength = size*1.5f;
		Body puck = BodyUtils.createCircle(world, x, y, size);
		float segmentThickness = size * .2f;
		int segments = 1;
		float cx = x;
		float cy = y;
		Material m = Material.RUBBER();
		m.setAngularDamping(0.1f);
		m.setLinearDamping(0.5f);
		m.setDensity(1.0f);
		for (int i=0; i<tendrils; ++i) {
			float tlength = tendrilLength;
			float xstart = cx+size*(float)Math.sin(i*2*3.14/tendrils);
			float ystart = cy+size*(float)Math.cos(i*2*3.14/tendrils);
			float xtarg = cx+(size+tlength)*(float)Math.sin(i*2*3.14/tendrils);
			float ytarg = cy+(size+tlength)*(float)Math.cos(i*2*3.14/tendrils);
			ArrayList<Body> bods = BodyUtils.createRope(world, new Vec2(xstart,ystart), 
				new Vec2(xtarg,ytarg), segmentThickness, segments);
			for (Body b:bods) {
				m.applyAll(b);
			}
			RevoluteJointDef rjd = new RevoluteJointDef();
			rjd.initialize(puck, bods.get(0), new Vec2(xstart,ystart));
			world.createJoint(rjd);
		}
		m.setDensity(10.0f);
		m.applyAll(puck);
		return puck;
	}
}
